/**
 * @file    gt98xx_drv_adc.c
 * @author  Giantec-Semi ATE
 * @brief   Source file of ADC DRV module.
 * @version 0.1
 * 
 * @copyright Copyright (c) 2021 Giantec-Semi
 */

#include "gt98xx_drv_adc.h"

/**
 * @addtogroup GT98xx_DRV
 * @{
 */
 
volatile uint32_t ADCReg_Cr0 = 0;
volatile uint32_t ADCReg_Bgcr0 = 0;
void Delay(volatile uint32_t time);
uint32_t adcdata1,adcdata2,adcdata3,adcdata4,adcdata5,adcdata6;//

#define   DMA_INT_ST 						(*(__IO uint32_t *)0x400111B0)
#define   DMA_INT_ST_CLR 				(*(__IO uint32_t *)0x400111B8)
#define 	ADC_INT_CLR           (*(__IO uint32_t *)0x40011F08)
 
 
void DrvAdcInit(void)
{
  static uint32_t dly;//zy
	
  
  DrvAdcBgTypedef bgcfg;
  DrvAdcPgaTypedef pgacfg;
  DrvAdcChannelTypedef chcfg;
  DrvAdcCfgTypedef adccfg;
  
	/*SET ADC CHANEL*/
  adccfg.ADC_Clk_Div = 5;
  adccfg.TS_Setup_Clk_Div = 0;
  adccfg.Pwr_Dly_Clk_Div = 0;
  //adccfg.Cont = DRV_ADC_MODEL_SINGLE;		//SINGLE CONVERT
	adccfg.Cont = DRV_ADC_MODEL_CONTINUE;
  adccfg.Scan = kEnable;									//SCAN MODE
  adccfg.Sq_Len = 7;  //XY
	adccfg.ADC_Trig_Sel = DRV_ADC_TRIG_SOFTWARE;//SOFTWARE TRIG
  
	/*SET ADC CHANEL*/
	chcfg.ChannelSel = DRV_ADC_CHANNELSEL_HALLX_TMR1;
	chcfg.HALLTMR_Sel = 0x01;     //SEL TMR  
	chcfg.Pga_EN = 0x07;
	chcfg.Chop_EN = 0;
	chcfg.Delay_EN=0;
	
	

  
	/*SET BAND GAP*/
  bgcfg.Cycle_Trig_Dly_Index = 0;
  bgcfg.Bg_Div_Index = 9;
  bgcfg.Bg_Chfre = DRV_ADC_BGCHFRE_CHOPBGCLK_DIV1;
	bgcfg.Bg_Chop_EN = kEnable;
	//bgcfg.Bg_Chop_EN = kDisable;
  bgcfg.Bg_EN = kEnable;
  bgcfg.Vref_EN = kEnable;
  
	/* SET HALL PGA GAIN = 10 */
	pgacfg.PGA_GainX = DRV_ADC_PGAGAINX_TMR2;
	//pgacfg.PGA_GainY = DRV_ADC_PGAGAINX_TMR2;

  
	/* CONFIG ADC PGA,BG*/
  DrvAdcCfg(&adccfg);
  DrvAdcPgaCfg(&pgacfg);
	DrvAdcBgChopCfg(&bgcfg);
  
  DrvAdcCalibrationCfg(16, 8, kEnable); 			//ADC  Calibration
	ADC->CR0 = ADCReg_Cr0 | ADC_CR0_ADC_EN;
  dly = 30000;
  while(dly)
    dly--;
	//DrvAdcSetBgEnVddDiv(ADC,1);
	DrvAdcChannelCfg(DRV_ADC_CH4, &chcfg);			//SET CH4,tmr1
	DrvAdcChannelCfg(DRV_ADC_CH5, &chcfg); 			//SET CH5,tmr1
	DrvAdcChannelCfg(DRV_ADC_CH6, &chcfg);			//SET CH6,tmr1
	DrvAdcChannelCfg(DRV_ADC_CH7, &chcfg);			//SET CH7,tmr1
	chcfg.ChannelSel = DRV_ADC_CHANNELSEL_TMR2;
	DrvAdcChannelCfg(DRV_ADC_CH8, &chcfg);			//SET CH8,tmr2
	DrvAdcChannelCfg(DRV_ADC_CH9, &chcfg);			//SET CH9,tmr2
	DrvAdcChannelCfg(DRV_ADC_CH10, &chcfg);			//SET CH10,tmr2
	DrvAdcChannelCfg(DRV_ADC_CH11, &chcfg);			//SET CH11,tmr2
	
	/*chcfg.ChannelSel = DRV_ADC_CHANNELSEL_HALLY_TMR3;
	DrvAdcChannelCfg(DRV_ADC_CH5, &chcfg);			//SET CH5,HALLY CH
	chcfg.ChannelSel = DRV_ADC_CHANNELSEL_HALLZ_TMR5;
	DrvAdcChannelCfg(DRV_ADC_CH6, &chcfg);	*/		//SET CH5,HALLY CH
	
}

void DrvAdcStart(void)
{
  SET_BIT(ADC->CR0, ADC_CR0_SWSTART);
}

void DrvAdcStop(void)
{
  CLEAR_BIT(ADC->CR0, ADC_CR0_SWSTART);
}

uint16_t MIDADC(uint16_t da1,uint16_t da2,uint16_t da3,uint16_t da4){
	uint16_t daa[4]={da1,da2,da3,da4};
	uint16_t temp_data;
	uint8_t i,j;
	i=0;
	j=3;
	while(j>0){
	while(i<j){
		if(daa[i]>daa[i+1]){
			temp_data=daa[i];
			daa[i]=daa[i+1];
			daa[i+1]=temp_data ;
		}
		i++;
	}
	i=0;
	j--;
}
	temp_data =daa[1]/2+daa[2]/2;
return temp_data ;
}

uint16_t DrvAdcGetHallCode(void)
{
  DrvAdcValuTypedef adchall1,adchall2,adchall3,adchall4;//
	uint32_t reg =0;
	//uint32_t adcdata1,adcdata2,adcdata3,adcdata4;//
  uint16_t hallxycode;
	
	//SINGLE CONVERT,start sw trig
	//CLEAR_BIT(ADC->CR0, ADC_CR0_SWSTART);
	//SET_BIT(ADC->CR0, ADC_CR0_SWSTART);
	
	while(reg != 0x00000010)		// sq_tr_int = 1 
	{
		reg = READ_REG(DMA_INT_ST);                
		reg &=0x00000010;
  }
	WRITE_REG(DMA_INT_ST_CLR, 0x0000001E);  //clear DMA_INT_ST 
	
  adcdata1 = READ_REG(ADC->DR);					//adc ch4 data
	while(((adcdata1>>15) & 0x00000001)!=0x00000001){
		adcdata1 = READ_REG(ADC->DR);	
	}
	
	adcdata2 = READ_REG(ADC->DR);         //adc ch5 data
	while(((adcdata2>>15) & 0x00000001)!=0x00000001){
		adcdata2 = READ_REG(ADC->DR);	
	}
	
	
	adcdata3 = READ_REG(ADC->DR);
	while(((adcdata3>>15) & 0x00000001)!=0x00000001){
		adcdata3 = READ_REG(ADC->DR);	
	}
	adcdata4 = READ_REG(ADC->DR);
	while(((adcdata4>>15) & 0x00000001)!=0x00000001){
		adcdata4 = READ_REG(ADC->DR);	
	}
	adcdata5 = READ_REG(ADC->DR);
	while(((adcdata5>>15) & 0x00000001)!=0x00000001){
		adcdata5= READ_REG(ADC->DR);	
	}
	adcdata6 = READ_REG(ADC->DR);
	while(((adcdata6>>15) & 0x00000001)!=0x00000001){
		adcdata6 = READ_REG(ADC->DR);	
	}
	adchall1.ChannelNum = (uint8_t)((adcdata1>>16) & 0x0000000F);    //ch_num [19:16] 
  adchall1.Flag = (uint8_t)((adcdata1>>15) & 0x00000001);         //data Valid flag [15] 
  adchall1.Valu = (uint16_t)(adcdata1 & 0x00007FFF);     //hallx code
	
	adchall2.ChannelNum = (uint8_t)((adcdata2>>16) & 0x0000000F);
  adchall2.Flag = (uint8_t)((adcdata2>>15) & 0x00000001);
  adchall2.Valu = (uint16_t)(adcdata2 & 0x00007FFF);		//hally code
	
	adchall3.ChannelNum = (uint8_t)((adcdata3>>16) & 0x0000000F);
  adchall3.Flag = (uint8_t)((adcdata3>>15) & 0x00000001);
  adchall3.Valu = (uint16_t)(adcdata3 & 0x00007FFF);		//hally code
	
	adchall4.ChannelNum = (uint8_t)((adcdata4>>16) & 0x0000000F);
  adchall4.Flag = (uint8_t)((adcdata4>>15) & 0x00000001);
  adchall4.Valu = (uint16_t)(adcdata4 & 0x00007FFF);		//hally code
	
  //hallxycode = adchall1.Valu;
	hallxycode = (adchall1.Valu/4+adchall2.Valu/4+adchall3.Valu/4+adchall4.Valu/4);
	//hallxycode =MIDADC(adchall1.Valu,adchall2.Valu,adchall3.Valu,adchall4.Valu);
  return hallxycode;
}

uint16_t DrvAdcGetHallCodey(void)
{
  DrvAdcValuTypedef adchallx,adchally,adchallz;//
	uint32_t reg =0;
	uint32_t adcdata1,adcdata2,adcdata3;//
  uint16_t hallxycode;
	
  adcdata1 = READ_REG(ADC->DR);					//adc ch4 data
	//adcdata2 = READ_REG(ADC->DR);         //adc ch5 data
	//adcdata3 = READ_REG(ADC->DR);
	adchallx.ChannelNum = (uint8_t)((adcdata1>>16) & 0x0000000F);    //ch_num [19:16] 
  adchallx.Flag = (uint8_t)((adcdata1>>15) & 0x00000001);         //data Valid flag [15] 
  adchallx.Valu = (uint16_t)(adcdata1 & 0x00007FFF);     //hallx code
	//adchally.ChannelNum = (uint8_t)((adcdata2>>16) & 0x0000000F);
  //adchally.Flag = (uint8_t)((adcdata2>>15) & 0x00000001);
  //adchally.Valu = (uint16_t)(adcdata2 & 0x00007FFF);		//hally code
	
	//adchallz.ChannelNum = (uint8_t)((adcdata3>>16) & 0x0000000F);
  //adchallz.Flag = (uint8_t)((adcdata3>>15) & 0x00000001);
  //adchallz.Valu = (uint16_t)(adcdata3 & 0x00007FFF);		//hally code
	
  //hallxycode = (adchallx.Valu<<16) + adchally.Valu;
	hallxycode = adchallx.Valu;
	
  return hallxycode;
}
DrvAdcValuTypedef DrvAdcGetValu(void)
{
  uint32_t reg;
  DrvAdcValuTypedef adcvalu;
  
  reg = READ_REG(ADC->DR);
  adcvalu.ChannelNum = (uint8_t)((reg>>16) & 0x0000000F);
  adcvalu.Flag = (uint8_t)((reg>>15) & 0x00000001);
  adcvalu.Valu = (uint16_t)(reg & 0x00007FFF);
  
  return adcvalu;
}

void DrvAdcCfg(DrvAdcCfgTypedef *cfgpara)
{
	DrvAdcSetPre(ADC, cfgpara->ADC_Clk_Div);
  DrvAdcSetTsSetupPara(ADC, cfgpara->TS_Setup_Clk_Div);
  DrvAdcSetPwrDlyPara(ADC, cfgpara->Pwr_Dly_Clk_Div);
  DrvAdcSetCont(ADC, cfgpara->Cont);
  DrvAdcSetScan(ADC, cfgpara->Scan);
  DrvAdcSetAdcTrig(ADC, cfgpara->ADC_Trig_Sel);
  DrvAdcSetSqTrLen(ADC, cfgpara->Sq_Len);
  
  if(cfgpara->Sq_First_Dly_EN)
  {
    ADCReg_Cr0 |= ADC_CR0_SQ_FIRST_DLY_EN;
  }
  else
  {
    ADCReg_Cr0 &= ~(ADC_CR0_SQ_FIRST_DLY_EN);
  }
  DrvAdcSetAdcTrim(ADC, 0x00000004);
	WRITE_REG(ADC->INT_CLR,0x1); 
  CLEAR_REG(ADC->DMA_INT_CR);
	DrvAdcSetDmaSqTrIntMask(ADC, kDisable);//kDisable
  DrvAdcSetDmaSingleTrIntMask(ADC, kEnable);
  DrvAdcSetDmaCcEocIntMask(ADC, kEnable);
  DrvAdcSetDmaBufOvIntMask(ADC, kEnable);
	//DrvAdcSetDmaSqTrDmaEn(ADC,kEnable);
	//DrvAdcSetDmaSingleTrDmaEn(ADC,kEnable);
}

void DrvAdcChannelCfg(uint8_t ch, DrvAdcChannelTypedef *chpara)
{
  if(chpara->ChannelSel == DRV_ADC_CHANNELSEL_VDD)
  {
    ADCReg_Bgcr0 |= ADC_BG_CR0_EN_VDDDIV;
  }
  if(chpara->ChannelSel == DRV_ADC_CHANNELSEL_VM)
  {
    ADCReg_Bgcr0 |= ADC_BG_CR0_EN_VMDIV;
  }

  if(chpara->TS1_EN)
  {
    ADCReg_Cr0 |= ADC_CR0_SQ_FIRST_TS1_EN;
  }
  else
  {
    ADCReg_Cr0 &= ~(ADC_CR0_SQ_FIRST_TS1_EN);
  }
  if(chpara->TS2_EN)
  {
    ADCReg_Cr0 |= ADC_CR0_TS2_EN;
  }
  else
  {
    ADCReg_Cr0 &= ~(ADC_CR0_TS2_EN);
  }
  if(chpara->Chop_EN)
  {
    ADCReg_Cr0 |= ADC_CR0_CHOP_EN;
  }
  else
  {
    ADCReg_Cr0 &= ~(ADC_CR0_CHOP_EN);
  }
  
  DrvAdcSetChChopFlag(ch, chpara->Chop_EN);
  DrvAdcSetChDlyFlag(ch, chpara->Delay_EN);
  DrvAdcSetChHallTmrSel(ch, chpara->HALLTMR_Sel);
  DrvAdcSetChPgaEn(ch, chpara->Pga_EN);
  DrvAdcSetChSqtrx(ch, chpara->ChannelSel);
}

void DrvAdcPgaCfg(DrvAdcPgaTypedef *pgapara)
{
  
	uint32_t pga_cr0_value = 0;																					
	pga_cr0_value = (((pgapara->PGA_GainX)&0xFF) << ADC_PGA_CR0_PGA_GAIN2X_Pos) + (((pgapara->PGA_GainY)&0x7F) << ADC_PGA_CR0_PGA_GAIN2Y_Pos) + (((pgapara->PGA_GainZ)&0x7F) << ADC_PGA_CR0_PGA_GAIN2Z_Pos)+ (pgapara->PGA_GainSMA&0x0F);
	ADC->PGA_CR0 = pga_cr0_value;

  
  if(pgapara->PGA_SMA_EN)
  {
    ADCReg_Bgcr0 |= ADC_BG_CR0_PGA_SMA_EN;
  }
  else
  {
    ADCReg_Bgcr0 &= ~(ADC_BG_CR0_PGA_SMA_EN);
  }
}

void DrvAdcBgChopCfg(DrvAdcBgTypedef *bgpara)
{
  uint32_t reg, dly;
  
  DrvAdcSetBgCycleTrigDlyIndex(ADC, bgpara->Cycle_Trig_Dly_Index);
  DrvAdcSetBgDivIndex(ADC, bgpara->Bg_Div_Index);
  DrvAdcSetBgChfre(ADC, bgpara->Bg_Chfre);
  if(bgpara->Bg_Chop_EN)
  {
    ADCReg_Bgcr0 |= ADC_BG_CR0_BG_CHOP_EN;
  }
  else
  {
    ADCReg_Bgcr0 &= ~(ADC_BG_CR0_BG_CHOP_EN);
  }
  if(bgpara->Bg_EN)
  {
    ADCReg_Bgcr0 |= ADC_BG_CR0_BG_EN;
  }
  else
  {
    ADCReg_Bgcr0 &= ~(ADC_BG_CR0_BG_EN);
  }
  if(bgpara->Vref_EN)
  {
    ADCReg_Bgcr0 |= ADC_BG_CR0_VREF_EN;
  }
  else
  {
    ADCReg_Bgcr0 &= ~(ADC_BG_CR0_VREF_EN);
  }
  
  DrvAdcSetBgTrim(ADC, 0x000000012);
  ADC->BG_CR0 |= ADCReg_Bgcr0;

  dly = 10000;
  while(dly--);
  
}
 
void DrvAdcCalibrationCfg(uint8_t time, uint8_t num, uint8_t state)
{
  DrvAdcSetChSqtrx(DRV_ADC_CH4, 0x0c);
	DrvAdcSetCalibTime(ADC, time);
  DrvAdcSetCalibBitNum(ADC, num);
  
  if(state)
  {
    ADCReg_Cr0 |= ADC_CR0_CALI_EN;
  }
  else
  {
    ADCReg_Cr0 &= ~(ADC_CR0_CALI_EN);
  }
}


/** @} GT98xx_DRI */


